using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(SimpleFellowCamera))]
[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(GUIJoySticks))]
public class SimpleCharacterCtrl : MonoBehaviour
{
    public enum MODE
    {
        CHARACTOR_CTRL,
        PHYSICS,
        NONE
       
    }

    public MODE mode = MODE.CHARACTOR_CTRL;
    public LayerMask groundMark = -1;
    public enum STATE
    {
        IDLE,
        RUN,
        JUMP
    }
    [Min(1f)]
    public float speed = 100f;
    public GUIJoySticks joysticks;
    public CharacterController characterController;
    public SimpleFellowCamera fellowCamera;
    
    public bool isLocal = false;

    STATE state = STATE.IDLE;

    public float jumpSpeed  = 10f;
    public float curJumpSpeed = 10;
    public Vector3 curJumpDir = Vector3.zero;

    public Animator animator;

    public string idleName= "idle";
    public string runName="run";

 
 
    AnimationClip runClip = null;
    // Start is called before the first frame update
    void Start()
    {
        joysticks = GetComponent<GUIJoySticks>();
        characterController = GetComponent<CharacterController>();
        if (null != characterController)
            characterController.center = Vector3.up;
        fellowCamera = GetComponent<SimpleFellowCamera>();
        fellowCamera.target = this.transform;
        fellowCamera.isLocal = isLocal;
        animator = GetComponentInChildren<Animator>();
        if (null != animator)
        {
            var animations = animator.runtimeAnimatorController.animationClips;
            for (int i = 0; i < animations.Length; ++i)
            {
                var anim = animations[i];
                
                if (idleName.Length==0 &&(anim.name.ToLower().Contains("idle")|| anim.name.ToLower().Contains("stand") || anim.name.ToLower().Contains("default")))
                {
                    idleName = anim.name;
                }
                else if (runName.Length == 0 &&(anim.name.ToLower().Contains("run") || anim.name.ToLower().Contains("walk")))
                {
                    runName = anim.name;
                    runClip = anim;
                }
            }
        }
       
    }

    bool artModel = true;
    bool hitGround = false;
 
    Vector3 lastOnGroud;
    // Update is called once per frame
    void Update()
    {

        if (mode == MODE.PHYSICS && artModel)
        {
            RaycastHit hit;
            var p = this.transform.position;
            if (Physics.Raycast(this.transform.position + Vector3.up * 100, Vector3.down, out hit, 200f, groundMark))
            {
                if (hit.point.y >= p.y)
                {
                    hitGround = true;
                    lastOnGroud = hit.point;


                }
            }
            else if (hitGround)
            {
                if (state == STATE.JUMP)
                {
                    p.x = lastOnGroud.x;
                    p.z = lastOnGroud.z;
                    this.transform.position = p;
                }
                else
                {
                    this.transform.position = lastOnGroud;
                }
            }
        }
        if (joysticks.DragingCamera)
        {
            this.fellowCamera.rotX +=   joysticks.DragCameraDir.y;
            this.fellowCamera.rotY +=  joysticks.DragCameraDir.x ;
            this.fellowCamera.FixData();



        }
        this.characterController.enabled =  mode == MODE.CHARACTOR_CTRL;


        if (state == STATE.JUMP)
        {
            if (joysticks.IsJump)
            {
                Vector3 forward = this.transform.forward;
                if (!isLocal)
                {
                    forward = fellowCamera.cam.transform.forward;
                }
                forward.y = 0;
                forward.Normalize();
                Vector3 left = Vector3.Cross(Vector3.up, forward);
                Vector3 dir = left * joysticks.dir.x + forward * joysticks.dir.y;
                dir.Normalize();
                state = STATE.JUMP;
                curJumpDir = dir;
                curJumpSpeed = jumpSpeed;
                this.transform.forward = curJumpDir;
                return;
            }
            float v0 = curJumpSpeed;
            float v1 = curJumpSpeed - 9.8f * Time.deltaTime;
            curJumpSpeed = v1;
            float s = (v0 + v1) * 0.5f * Time.deltaTime;
            if (mode == MODE.CHARACTOR_CTRL)
            {
                characterController.Move(curJumpDir * Time.deltaTime * speed + Vector3.up * s);
            }
            else
            {
                Move(curJumpDir * Time.deltaTime * speed + Vector3.up * s);
            }
            if (IsOnGround())
            {
                state = STATE.IDLE;
            }
            return;
        }
        if (joysticks.dir.magnitude > 0)
        {
            Vector3 forward = this.transform.forward;
            if (!isLocal)
            {
                forward = fellowCamera.cam.transform.forward;
            }
            forward.y = 0;
            forward.Normalize();
            Vector3 left = Vector3.Cross(Vector3.up, forward);
            Vector3 dir = left * joysticks.dir.x + forward * joysticks.dir.y;
            dir.Normalize();

            if (joysticks.IsJump)
            {
                state = STATE.JUMP;
                curJumpDir = dir;
                curJumpSpeed = jumpSpeed;
                this.transform.forward = curJumpDir;
            }
            else
            {
                
                if (mode == MODE.CHARACTOR_CTRL)
                {
                    characterController.SimpleMove(dir * Time.deltaTime * speed);
                }
                if (mode == MODE.NONE)
                {
                    Move(dir * Time.deltaTime * speed);
                }
                else
                {
                    Move(dir * Time.deltaTime * speed);
                    FixToGround();
                }
                

                if (state != STATE.RUN)
                {
                    state = STATE.RUN;
                    if (null != animator)
                        animator.Play(runName, -1);
                }

                /*Vector3 forward0 = this.transform.forward;
                if (Vector3.Dot(forward0, dir) < -0.9f)
                {

                    this.transform.forward = Vector3.MoveTowards(this.transform.forward, this.transform.right, Time.deltaTime * 30f);
                }
                else
                {
                    this.transform.forward = Vector3.MoveTowards(this.transform.forward, dir, Time.deltaTime * 30f);
                }*/
                this.transform.forward = dir;
            }
        }

        else
        {
            if (joysticks.IsJump)
            {
       
                state = STATE.JUMP;
                curJumpDir = Vector3.zero;
                curJumpSpeed = jumpSpeed;
                
            }
            else
            {
                if (state != STATE.IDLE)
                {
                    state = STATE.IDLE;
                    if (null != animator)
                        animator.Play(idleName, -1);
                }
                
            }

        }
    }

    private bool IsOnGround()
    {
        if (mode == MODE.CHARACTOR_CTRL)
        {
            return characterController.collisionFlags == CollisionFlags.Below;
        }
        else
        {
            RaycastHit hit;
            var p = this.transform.position;
            if (Physics.Raycast(this.transform.position + Vector3.up, Vector3.down, out hit,5f , groundMark))
            {
                if (hit.point.y >= p.y)
                {
                    p.y = hit.point.y;
                    this.transform.position = p;
        
                    return true;
                }
            }

            return false;
        }
    }
 
    
    private void FixToGround()
    {
        if (mode == MODE.CHARACTOR_CTRL)
        {
            
        }
        else
        {
            RaycastHit hit;
            var p = this.transform.position;
            if (Physics.Raycast(this.transform.position + Vector3.up, Vector3.down, out hit, 10f, groundMark))
            {
     
                this.transform.position = hit.point;
                lastOnGroud = hit.point;


            }
            else if(hitGround)
            {
                this.transform.position = lastOnGroud;
            }
            

       
        }
    }

    private void Move(Vector3 vector3)
    {
        this.transform.position += vector3;
    }
}
